package com.ashlikun.zxing.able

import android.graphics.Rect
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import com.ashlikun.zxing.Config
import com.ashlikun.zxing.TypeRunnable
import com.ashlikun.zxing.WorkThreadServer
import com.ashlikun.zxing.core.Dispatch
import com.ashlikun.zxing.core.GrayScaleDispatch
import com.ashlikun.zxing.helper.ScanHelper
import com.google.zxing.PlanarYUVLuminanceSource
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.system.measureNanoTime
import kotlin.system.measureTimeMillis
import kotlin.time.measureTime

/**
 * @author　　: 李坤
 * 创建时间: 2022/5/2 20:48
 * 邮箱　　：496546144@qq.com
 *
 * 功能介绍：
 */
class AbleManager private constructor(handler: Handler) : com.ashlikun.zxing.able.PixsValuesAble(handler) {

    private val ableList = CopyOnWriteArrayList<com.ashlikun.zxing.able.PixsValuesAble>()

    private var server: WorkThreadServer = WorkThreadServer.createInstance()

    private var processDispatch: Dispatch? = null

    private var grayProcessHandler: Handler? = null

    init {
        loadAbility()
        if (Config.hasDepencidesScale()) {
            processDispatch = GrayScaleDispatch
        }
        grayProcessHandler = Handler(HandlerThread("GrayProcessThread")
            .apply { start() }
            .looper)
    }

    fun loadAbility() {
        ableList.clear()
        ableList.apply {
            add(XQRScanCrudeAble(handlerHolder.get()))
            if (Config.isSupportAutoZoom)
                add(XQRScanZoomAble(handlerHolder.get()))
            else add(XQRScanAble(handlerHolder.get()))
            add(XQRScanAbleRotate(handlerHolder.get()))
            add(LighSolveAble(handlerHolder.get()))
        }
//        ableList.add(XQRScanAble(handlerHolder.get()))
//        ableList.add(GrayscaleStrengAble(handlerHolder.get()))
    }

    /**
     * 相机实时数据解析
     */
    public override fun cusAction(data: ByteArray, dataWidth: Int, dataHeight: Int) {
        val aa = measureTimeMillis {
            executeToParseWay2(data, dataWidth, dataHeight, ScanHelper.getScanByteRect(dataWidth, dataHeight))
        }
        Log.e("解析一针数据时间", aa.toString())
    }

    /***
     * 灰度处理后解析
     */
    private fun grayscaleProcess(source: PlanarYUVLuminanceSource) {
        grayProcessHandler?.removeCallbacksAndMessages(null)
        grayProcessHandler?.post {
            processDispatch!!.dispatch(source.matrix, source.width, source.height)
            for (able in ableList) {
                //任务是否可以执行(由任务内部逻辑实现)
                if (able.isCycleRun(false)) {
                    //线程池推送任务
                    server.post(TypeRunnable.create(able.provideType(false)) {
                        able.cusAction(source.matrix, source.width, source.height, false)
                        able.needParseDeploy(source, false)
                    })
                }
            }
        }
    }

    /***
     *  解析原始数据
     */
    private fun originProcess(
        source: PlanarYUVLuminanceSource,
        data: ByteArray,
        dataWidth: Int,
        dataHeight: Int
    ) {
        ableList.forEach { able ->
            if (able.isCycleRun(true))
                server.post(TypeRunnable.create(able.provideType(true)) {
                    able.cusAction(data, dataWidth, dataHeight, true)
                    able.needParseDeploy(source, true)
                })
        }
    }

    /***
     * 任务调度
     * 方式二： 直接拷贝一份ByteArray同时处理原始数据与灰度变换后的数据
     * 该方式速度快，占用内存较高
     */
    private fun executeToParseWay2(data: ByteArray, dataWidth: Int, dataHeight: Int, rect: Rect) {
        //生成全局YUVLuminanceSource
        val oriSource = generateGlobeYUVLuminanceSource(data, dataWidth, dataHeight, rect) ?: return
        //执行原始数据解析
        originProcess(oriSource, data, dataWidth, dataHeight)
        //copy一份相同的数据后处理灰度
        val graySource = oriSource.copyAll()
        if (processDispatch != null)
            grayscaleProcess(graySource)
    }

    private fun generateGlobeYUVLuminanceSource(
        data: ByteArray?,
        dataWidth: Int,
        dataHeight: Int,
        rect: Rect
    ): PlanarYUVLuminanceSource? {
        return com.ashlikun.zxing.helper.ScanHelper.buildLuminanceSource(data, dataWidth, dataHeight, rect)
    }

    companion object {
        fun createInstance(handler: Handler): AbleManager {
            return AbleManager(handler)
        }
    }

    override fun release() {
        ableList.forEach { it.release() }
        ableList.clear()
        server.quit()
        if (processDispatch == null) return
        grayProcessHandler?.removeCallbacksAndMessages(null)
        grayProcessHandler?.looper?.quit()
        grayProcessHandler = null
    }

    fun clear() {
        server.clear()
        ableList.clear()
    }

}